﻿namespace Resharper.Abstractions.LiveTemplates
{
  using System;
  using System.Collections.Generic;
  using System.Xml;
  using AgentJohnson.SmartGenerators;
  using JetBrains.Annotations;
  using JetBrains.Application;
  using JetBrains.ReSharper.Feature.Services.LiveTemplates.LiveTemplates;
  using JetBrains.ReSharper.Feature.Services.LiveTemplates.Storages;
  using JetBrains.ReSharper.LiveTemplates.UI.TemplateEditor;
  using Resharper.Abstractions.Shell;

  /// <summary>Defines the <see cref="LiveTemplateManager"/> class.</summary>
  public static class LiveTemplateManager
  {
    #region Constants and Fields

    /// <summary>The do not change field.</summary>
    private const string DoNotChange = "`Do not change: ";

    #endregion

    #region Public Methods

    /// <summary>Creates the live template.</summary>
    public static void CreateLiveTemplate(string key, string description, string text)
    {
      var template = new JetBrains.ReSharper.LiveTemplates.Templates.Template(DoNotChange + key, description, text ?? string.Empty, true, true, false);

      var templateManager = Shell.Instance.GetComponent<LiveTemplatesManager>();
      var templateStorage = templateManager.TemplateFamily.UserStorage;

      foreach (var storage in templateManager.TemplateFamily.TemplateStorages)
      {
        if (storage is FileStorage && !storage.ReadOnly)
        {
          templateStorage = storage;
          break;
        }
      }

      var templateEditorManager = Shell.Instance.GetComponent<TemplateEditorManager>();

      ShellManager.ExecuteReentrancyGuard("Smart Generate Create Template", () => templateEditorManager.CreateTemplate(template, templateStorage));
    }

    /// <summary>Gets the live templates.</summary>
    /// <param name="scope">The scope.</param>
    /// <returns>Returns the live templates.</returns>
    public static IEnumerable<LiveTemplate> GetLiveTemplates(ScopeInstance scope)
    {
      var s = DoNotChange + scope.Shortcut;

      var templateManager = Shell.Instance.GetComponent<LiveTemplatesManager>();
      foreach (var templateStorage in templateManager.TemplateFamily.TemplateStorages)
      {
        foreach (var template in templateStorage.Templates)
        {
          if (template.Shortcut == s)
          {
            yield return new LiveTemplate(template, scope);
          }
        }
      }
    }

    /// <summary>Gets the live templates.</summary>
    /// <param name="context">The context.</param>
    /// <param name="liveTemplate">The live template.</param>
    /// <param name="variables">The variables.</param>
    public static void ExecuteLiveTemplate([NotNull] DataContext context, [NotNull] string liveTemplate, [NotNull] string[] variables)
    {
      if (context == null)
      {
        throw new ArgumentNullException("context");
      }

      if (liveTemplate == null)
      {
        throw new ArgumentNullException("liveTemplate");
      }

      if (variables == null)
      {
        throw new ArgumentNullException("variables");
      }

      var solution = context.InternalDataContext.GetData(JetBrains.ProjectModel.DataContext.DataConstants.SOLUTION);
      if (solution == null)
      {
        return;
      }

      var textControl = context.InternalDataContext.GetData(JetBrains.TextControl.DataContext.DataConstants.TEXT_CONTROL);
      if (textControl == null)
      {
        return;
      }

      var vars = string.Empty;

      for (var index = 0; index < variables.Length - 1; index += 2)
      {
        var name = variables[index];
        var value = variables[index + 1];

        vars += string.Format("<Variable name=\"{0}\" expression=\"{1}\" initialRange=\"0\" />", name, value);
      }

      var text = string.Format("<Template text=\"{0}\" shortcut=\"\" description=\"\" reformat=\"true\" shortenQualifiedReferences=\"true\"><Variables>{1}</Variables></Template>", liveTemplate, vars);
      var doc = new XmlDocument();
      doc.LoadXml(text);
      var element = doc.DocumentElement;
      if (element == null)
      {
        return;
      }

      var templateManager = Shell.Instance.GetComponent<LiveTemplatesManager>();

      var templateFamily = templateManager.TemplateFamily;

      var template = JetBrains.ReSharper.LiveTemplates.Templates.Template.CreateFromXml(templateFamily.UserStorage, element);

      var hotSpot = templateManager.CreateHotspotSessionFromTemplate(template, solution, textControl);
      if (hotSpot != null)
      {
        hotSpot.Execute();
      }
    }

    #endregion
  }
}